﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// WebSocket 打印服务器
/// </summary>
public class WssPrintServer : IDisposable
{
    /// <summary>
    /// 客户端连接事件
    /// </summary>
    public event Action<string> OnClientConnected;

    /// <summary>
    /// 客户端断开连接事件
    /// </summary>
    public event Action<string> OnClientDisconnected;

    /// <summary>
    /// 收到客户端消息事件
    /// </summary>
    public event Action<string, string> OnMessageReceived; // 客户端ID, 消息内容

    /// <summary>
    /// 错误发生事件
    /// </summary>
    public event Action<Exception> OnErrorOccurred;

    private readonly HttpListener _httpListener;
    private readonly string _serverUrl;
    private CancellationTokenSource _cancellationTokenSource;
    private bool _isRunning;
    private bool _isDisposed;
    private readonly Dictionary<string, WebSocket> _connectedClients = new Dictionary<string, WebSocket>();
    private readonly object _clientsLock = new object();

    /// <summary>
    /// 服务器是否正在运行
    /// </summary>
    public bool IsRunning => _isRunning;

    /// <summary>
    /// 已连接的客户端数量
    /// </summary>
    public int ConnectedClientsCount
    {
        get
        {
            lock (_clientsLock)
            {
                return _connectedClients.Count;
            }
        }
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="serverUrl">服务器监听地址，例如 "http://localhost:8080/ws"</param>
    public WssPrintServer(string serverUrl)
    {
        if (string.IsNullOrEmpty(serverUrl))
            throw new ArgumentNullException(nameof(serverUrl));

        if (!serverUrl.StartsWith("http://") && !serverUrl.StartsWith("https://"))
            throw new ArgumentException("服务器地址必须使用 http 或 https 协议", nameof(serverUrl));

        _serverUrl = serverUrl;
        _httpListener = new HttpListener();
        _httpListener.Prefixes.Add(serverUrl);
    }

    /// <summary>
    /// 启动服务器
    /// </summary>
    public async Task StartAsync()
    {
        if (_isRunning)
            return;

        try
        {
            _httpListener.Start();
            _isRunning = true;
            _cancellationTokenSource = new CancellationTokenSource();

            await ListenForConnectionsAsync();
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(ex);
            Stop();
        }
    }

    /// <summary>
    /// 停止服务器
    /// </summary>
    public void Stop()
    {
        if (!_isRunning)
            return;

        _isRunning = false;
        _cancellationTokenSource?.Cancel();
        _httpListener.Stop();

        // 关闭所有客户端连接
        CloseAllClientConnections();
    }

    /// <summary>
    /// 监听客户端连接
    /// </summary>
    private async Task ListenForConnectionsAsync()
    {
        try
        {
            while (_isRunning && !_cancellationTokenSource.Token.IsCancellationRequested)
            {
                var context = await _httpListener.GetContextAsync();

                // 检查是否是WebSocket请求
                if (context.Request.IsWebSocketRequest)
                {
                    _ = HandleWebSocketConnectionAsync(context);
                }
                else
                {
                    // 不是WebSocket请求，返回400错误
                    context.Response.StatusCode = 400;
                    context.Response.Close();
                }
            }
        }
        catch (OperationCanceledException)
        {
            // 预期的取消操作，不视为错误
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(ex);
        }
    }

    /// <summary>
    /// 处理WebSocket连接
    /// </summary>
    private async Task HandleWebSocketConnectionAsync(HttpListenerContext context)
    {
        WebSocketContext webSocketContext = null;
        WebSocket webSocket = null;
        string clientId = Guid.NewGuid().ToString();

        try
        {
            webSocketContext = await context.AcceptWebSocketAsync(null);
            webSocket = webSocketContext.WebSocket;

            // 添加客户端到连接列表
            lock (_clientsLock)
            {
                _connectedClients[clientId] = webSocket;
            }

            // 触发客户端连接事件
            OnClientConnected?.Invoke(clientId);

            // 开始接收客户端消息
            await ReceiveClientMessagesAsync(clientId, webSocket);
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(new Exception($"客户端 {clientId} 处理错误: {ex.Message}", ex));
        }
        finally
        {
            // 清理客户端连接
            await CleanupClientConnection(clientId, webSocket);
        }
    }

    /// <summary>
    /// 接收客户端消息
    /// </summary>
    private async Task ReceiveClientMessagesAsync(string clientId, WebSocket webSocket)
    {
        var buffer = new byte[1024 * 4]; // 4KB 缓冲区

        while (_isRunning && webSocket.State == WebSocketState.Open)
        {
            try
            {
                var result = await webSocket.ReceiveAsync(
                    new ArraySegment<byte>(buffer),
                    _cancellationTokenSource.Token);

                if (result.MessageType == WebSocketMessageType.Close)
                {
                    await webSocket.CloseAsync(
                        WebSocketCloseStatus.NormalClosure,
                        "正常关闭",
                        CancellationToken.None);
                    break;
                }

                if (result.MessageType == WebSocketMessageType.Text)
                {
                    var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
                    OnMessageReceived?.Invoke(clientId, message);
                }
            }
            catch (OperationCanceledException)
            {
                // 预期的取消操作，不视为错误
                break;
            }
            catch (Exception ex)
            {
                OnErrorOccurred?.Invoke(new Exception($"接收客户端 {clientId} 消息错误: {ex.Message}", ex));
                break;
            }
        }
    }

    /// <summary>
    /// 向指定客户端发送消息
    /// </summary>
    /// <param name="clientId">客户端ID</param>
    /// <param name="message">消息内容</param>
    public async Task SendToClientAsync(string clientId, string message)
    {
        if (string.IsNullOrEmpty(clientId))
            throw new ArgumentNullException(nameof(clientId));

        if (string.IsNullOrEmpty(message))
            throw new ArgumentNullException(nameof(message));

        WebSocket clientWebSocket;
        lock (_clientsLock)
        {
            if (!_connectedClients.TryGetValue(clientId, out clientWebSocket))
                throw new KeyNotFoundException($"客户端 {clientId} 未连接");
        }

        try
        {
            var bytes = Encoding.UTF8.GetBytes(message);
            await clientWebSocket.SendAsync(
                new ArraySegment<byte>(bytes),
                WebSocketMessageType.Text,
                true,
                _cancellationTokenSource.Token);
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(new Exception($"向客户端 {clientId} 发送消息错误: {ex.Message}", ex));
            // 发送失败，移除客户端
            await CleanupClientConnection(clientId, clientWebSocket);
        }
    }

    /// <summary>
    /// 向所有客户端广播消息
    /// </summary>
    /// <param name="message">消息内容</param>
    public async Task BroadcastAsync(string message)
    {
        if (string.IsNullOrEmpty(message))
            throw new ArgumentNullException(nameof(message));

        List<string> clientIds;
        lock (_clientsLock)
        {
            clientIds = new List<string>(_connectedClients.Keys);
        }

        foreach (var clientId in clientIds)
        {
            try
            {
                await SendToClientAsync(clientId, message);
            }
            catch (Exception ex)
            {
                OnErrorOccurred?.Invoke(new Exception($"广播消息到客户端 {clientId} 失败: {ex.Message}", ex));
            }
        }
    }

    /// <summary>
    /// 清理客户端连接
    /// </summary>
    private async Task CleanupClientConnection(string clientId, WebSocket webSocket)
    {
        // 从连接列表中移除客户端
        lock (_clientsLock)
        {
            _connectedClients.Remove(clientId);
        }

        // 触发客户端断开连接事件
        OnClientDisconnected?.Invoke(clientId);

        // 关闭WebSocket连接
        if (webSocket != null && webSocket.State != WebSocketState.Closed &&
            webSocket.State != WebSocketState.Aborted)
        {
            try
            {
                await webSocket.CloseAsync(
                    WebSocketCloseStatus.NormalClosure,
                    "关闭连接",
                    CancellationToken.None);
            }
            catch (Exception ex)
            {
                OnErrorOccurred?.Invoke(new Exception($"关闭客户端 {clientId} 连接错误: {ex.Message}", ex));
            }
        }

        webSocket?.Dispose();
    }

    /// <summary>
    /// 关闭所有客户端连接
    /// </summary>
    private void CloseAllClientConnections()
    {
        List<WebSocket> clients;
        lock (_clientsLock)
        {
            clients = new List<WebSocket>(_connectedClients.Values);
            _connectedClients.Clear();
        }

        foreach (var client in clients)
        {
            try
            {
                if (client.State != WebSocketState.Closed && client.State != WebSocketState.Aborted)
                {
                    client.Dispose();
                }
            }
            catch (Exception ex)
            {
                OnErrorOccurred?.Invoke(ex);
            }
        }
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    /// <param name="disposing">是否手动释放</param>
    protected virtual void Dispose(bool disposing)
    {
        if (_isDisposed)
            return;

        if (disposing)
        {
            // 释放托管资源
            Stop();
            _httpListener.Close();
            _cancellationTokenSource?.Dispose();
        }

        _isDisposed = true;
    }

    /// <summary>
    /// 析构函数
    /// </summary>
    ~WssPrintServer()
    {
        Dispose(false);
    }
}
